<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8"/>
    <title>批量URL转二维码工具(离线版)</title>
    <script src="https://cdn.jsdelivr.net/npm/qrcode/build/qrcode.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/exceljs/4.4.0/exceljs.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
    <style>
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            padding: 20px;
            background-color: #f5f5f5;
            margin: 0;
        }
        .container {
            max-width: 1200px;
            margin: 0 auto;
            background: white;
            padding: 30px;
            border-radius: 10px;
            box-shadow: 0 4px 6px rgba(0,0,0,0.1);
        }
        h1 {
            text-align: center;
            color: #333;
            margin-bottom: 30px;
        }
        .input-section {
            margin-bottom: 30px;
        }
        .input-section label {
            display: block;
            margin-bottom: 10px;
            font-weight: bold;
            color: #555;
        }
        textarea {
            width: 100%;
            height: 200px;
            padding: 10px;
            border: 2px solid #ddd;
            border-radius: 5px;
            font-size: 14px;
            box-sizing: border-box;
        }
        .stats-panel {
            background-color: #f8f9fa;
            border: 1px solid #e9ecef;
            border-radius: 8px;
            padding: 20px;
            margin: 20px 0;
        }
        .stats-row {
            display: flex;
            justify-content: space-between;
            margin-bottom: 10px;
        }
        .stats-item {
            text-align: center;
            flex: 1;
        }
        .stats-number {
            font-size: 24px;
            font-weight: bold;
            color: #007bff;
        }
        .stats-label {
            font-size: 14px;
            color: #6c757d;
            margin-top: 5px;
        }
        .button-group {
            display: flex;
            gap: 15px;
            justify-content: center;
            margin: 20px 0;
            flex-wrap: wrap;
        }
        button {
            padding: 12px 24px;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            font-size: 16px;
            font-weight: bold;
            transition: background-color 0.3s;
        }
        .btn-primary {
            background-color: #007bff;
            color: white;
        }
        .btn-primary:hover {
            background-color: #0056b3;
        }
        .btn-success {
            background-color: #28a745;
            color: white;
        }
        .btn-success:hover {
            background-color: #1e7e34;
        }
        .btn-info {
            background-color: #17a2b8;
            color: white;
        }
        .btn-info:hover {
            background-color: #117a8b;
        }
        .btn-warning {
            background-color: #ffc107;
            color: #212529;
        }
        .btn-warning:hover {
            background-color: #e0a800;
        }
        .qrcode-container {
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
            gap: 20px;
            margin-top: 30px;
        }
        .qrcode-item {
            background: white;
            border: 1px solid #ddd;
            border-radius: 8px;
            padding: 15px;
            text-align: center;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }
        .qrcode-item img {
            max-width: 100%;
            height: auto;
        }
        .url-text {
            margin: 10px 0;
            word-break: break-all;
            font-size: 12px;
            color: #666;
            background: #f8f9fa;
            padding: 8px;
            border-radius: 4px;
        }
        .progress-bar {
            width: 100%;
            height: 20px;
            background-color: #e9ecef;
            border-radius: 10px;
            overflow: hidden;
            margin: 20px 0;
        }
        .progress-fill {
            height: 100%;
            background-color: #007bff;
            width: 0%;
            transition: width 0.3s ease;
        }
        .alert {
            padding: 15px;
            margin: 15px 0;
            border-radius: 5px;
            font-weight: bold;
        }
        .alert-warning {
            background-color: #fff3cd;
            border: 1px solid #ffeaa7;
            color: #856404;
        }
        .alert-success {
            background-color: #d4edda;
            border: 1px solid #c3e6cb;
            color: #155724;
        }
        .alert-error {
            background-color: #f8d7da;
            border: 1px solid #f5c6cb;
            color: #721c24;
        }
        .contact-section {
            margin-top: 40px;
            text-align: center;
        }
        .contact-header {
            margin-bottom: 25px;
        }
        .contact-header h2 {
            color: #333;
            font-size: 24px;
            margin-bottom: 10px;
            font-weight: 700;
        }
        .contact-subtitle {
            color: #666;
            font-size: 16px;
            margin: 0;
            font-weight: 400;
        }

        .service-info {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            border-radius: 15px;
            padding: 20px;
            color: white;
            margin-bottom: 25px;
        }
        .service-content-wrapper {
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 30px;
        }
        .service-items {
            display: flex;
            gap: 35px;
        }
        .service-item {
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 8px;
            min-width: 100px;
        }
        .service-icon {
            font-size: 28px;
            margin-bottom: 5px;
        }
        .service-item span:last-child {
            font-size: 16px;
            font-weight: 500;
        }
        .arrow-pointer {
            display: flex;
            flex-direction: row;
            align-items: center;
            gap: 8px;
            padding: 0 15px;
        }
        .arrow-text {
            font-size: 12px;
            font-weight: 500;
            color: rgba(255,255,255,0.9);
            white-space: nowrap;
        }
        .arrow-down {
            font-size: 16px;
            color: rgba(255,255,255,0.8);
            animation: pulse 2s infinite;
        }
        @keyframes pulse {
            0%, 100% {
                transform: scale(1);
                opacity: 0.8;
            }
            50% {
                transform: scale(1.1);
                opacity: 1;
            }
        }
        @keyframes spin {
            0% {
                transform: rotate(0deg);
            }
            100% {
                transform: rotate(360deg);
            }
        }
        .btn-loading {
            background-color: #6c757d !important;
            cursor: not-allowed !important;
            opacity: 0.8;
        }
        .btn-loading:hover {
            background-color: #6c757d !important;
        }
        .loading-icon {
            display: inline-block;
            animation: spin 1s linear infinite;
        }
        .qr-wrapper {
            display: flex;
            gap: 20px;
            align-items: center;
        }
        .qr-item {
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 8px;
        }
        .qr-label {
            font-size: 14px;
            font-weight: 600;
            color: white;
            margin-bottom: 5px;
        }
        .qr-mini-image {
            width: 80px;
            height: 80px;
            border-radius: 8px;
            border: 2px solid rgba(255,255,255,0.3);
            box-shadow: 0 2px 8px rgba(0,0,0,0.2);
        }
        .qr-tag {
            background: rgba(255,255,255,0.2);
            color: white;
            padding: 4px 8px;
            border-radius: 12px;
            font-size: 11px;
            font-weight: 500;
            backdrop-filter: blur(10px);
        }
        .qr-link {
            background: rgba(255,255,255,0.2);
            color: white;
            padding: 4px 12px;
            border-radius: 12px;
            text-decoration: none;
            font-size: 11px;
            font-weight: 500;
            backdrop-filter: blur(10px);
            transition: all 0.3s ease;
        }
        .qr-link:hover {
            background: rgba(255,255,255,0.3);
            color: white;
            text-decoration: none;
            transform: scale(1.05);
        }
        @media (max-width: 768px) {
            .contact-header h2 {
                font-size: 24px;
            }
            .service-content-wrapper {
                flex-direction: column;
                gap: 20px;
            }
            .service-items {
                gap: 20px;
                justify-content: center;
            }
            .service-item {
                min-width: 80px;
            }
            .service-icon {
                font-size: 24px;
            }
            .service-item span:last-child {
                font-size: 14px;
            }
            .arrow-pointer {
                padding: 0;
            }
            .arrow-text {
                font-size: 11px;
            }
            .arrow-down {
                font-size: 14px;
            }
            .qr-wrapper {
                gap: 15px;
                flex-wrap: wrap;
                justify-content: center;
            }
            .qr-mini-image {
                width: 55px;
                height: 55px;
            }
            .qr-tag, .qr-link {
                font-size: 10px;
                padding: 3px 8px;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>🚀 批量URL转二维码工具(离线版)</h1>
        
        <div class="input-section">
            <label for="urlInput">输入 URL 地址（每行一个，最多支持5000个）：</label>
            <textarea id="urlInput" placeholder="请输入 URL 地址，每行一个，例如：
https://www.example.com
https://www.google.com
https://www.github.com"></textarea>
        </div>

        <!-- 统计信息面板 -->
        <div class="stats-panel">
            <div class="stats-row">
                <div class="stats-item">
                    <div class="stats-number" id="totalUrls">0</div>
                    <div class="stats-label">总链接数</div>
                </div>
                <div class="stats-item">
                    <div class="stats-number" id="validUrls">0</div>
                    <div class="stats-label">有效链接</div>
                </div>
                <div class="stats-item">
                    <div class="stats-number" id="generatedQr">0</div>
                    <div class="stats-label">已生成二维码</div>
                </div>
                <div class="stats-item">
                    <div class="stats-number" id="shortUrls">0</div>
                    <div class="stats-label">短链接数</div>
                </div>
            </div>
        </div>

        <!-- 进度条 -->
        <div class="progress-bar" id="progressContainer" style="display: none;">
            <div class="progress-fill" id="progressBar"></div>
        </div>

        <!-- 按钮组 -->
        <div class="button-group">
            <button id="generateBtn" class="btn-primary" onclick="generateAllQRCodes()">📱 批量生成二维码</button>
            <button class="btn-success" onclick="downloadAllQRCodeImages()">📦 下载二维码压缩包</button>
            <button class="btn-info" onclick="exportToExcel()">📊 导出Excel文件</button>
            <button class="btn-warning" onclick="clearAll()">🗑️ 清空所有</button>
        </div>

        <!-- 提示信息 -->
        <div id="alertContainer"></div>

        <!-- 二维码显示区域 -->
        <div id="previewInfo" style="display: none; text-align: center; margin: 20px 0; padding: 15px; background-color: #e7f3ff; border: 1px solid #b3d9ff; border-radius: 8px; color: #0056b3;">
            <strong>📱 二维码预览区域</strong><br>
            <small>页面仅显示前8个二维码预览，所有二维码均已生成完成并可导出（文件名已嵌入图片中）</small>
        </div>
        <div class="qrcode-container" id="qrcodeContainer"></div>
        
        <!-- 联系作者区域 -->
        <div class="contact-section">
            <hr style="margin: 40px 0; border: none; border-top: 2px solid #e9ecef;">
            
            <!-- 标题区域 -->
            <div class="contact-header">
                <h2>💡 需要定制功能？联系作者！</h2>
                <p class="contact-subtitle">快速响应 · 贴心服务 · 只需一杯咖啡</p>
            </div>
            
            <!-- 服务说明 -->
            <div class="service-info">
                <div class="service-content-wrapper">
                    <!-- 功能说明 -->
                    <div class="service-items">
                        <div class="service-item">
                            <span class="service-icon">🚀</span>
                            <span>功能优化</span>
                        </div>
                        <div class="service-item">
                            <span class="service-icon">✨</span>
                            <span>新增功能</span>
                        </div>
                        <div class="service-item">
                            <span class="service-icon">🎨</span>
                            <span>UI美化</span>
                        </div>
                        <div class="service-item">
                            <span class="service-icon">⚡</span>
                            <span>性能提升</span>
                        </div>
                    </div>
                    
                    <!-- 箭头指向 -->
                    <div class="arrow-pointer">
                        <span class="arrow-text">扫码联系</span>
                        <div class="arrow-down">➤</div>
                    </div>
                    
                    <!-- 联系方式 -->
                    <div class="qr-wrapper">
                        <div class="qr-item">
                            <div class="qr-label">📱 联系作者</div>
                            <img src="https://tupian.li/images/2025/07/06/686a9d4bc5285.jpg?resource_id=2204587658931&region=0&w=2000&q=80" 
                                 alt="联系作者二维码" 
                                 class="qr-mini-image">
                            <a href="https://gitee.com/icanxx" 
                               target="_blank" 
                               rel="noopener noreferrer"
                               class="qr-link">
                               🔗 作者主页
                            </a>
                        </div>
                        
                        
                        <div class="qr-item">
                            <div class="qr-label">☕ 请杯咖啡</div>
                            <img src="https://tupian.li/images/2025/07/07/686a9df8f1839.webp?resource_id=2204588512275&region=0&w=2000&q=80" 
                                 alt="微信支付二维码" 
                                 class="qr-mini-image">
                            <div class="qr-tag">💰 一杯咖啡</div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <script>
        let qrData = []; // 存储所有二维码数据
        let isGenerating = false;

        // 实时统计URL输入
        document.getElementById('urlInput').addEventListener('input', function() {
            updateStats();
        });
		
		/**
		 * 获取当前时间戳字符串
		 * @returns {string} 格式化的时间戳
		 */
		function getCurrentTimestamp() {
		    const now = new Date();
		    const year = String(now.getFullYear());
		    const month = String(now.getMonth() + 1).padStart(2, '0');
		    const day = String(now.getDate()).padStart(2, '0');
		    const hours = String(now.getHours()).padStart(2, '0');
		    const minutes = String(now.getMinutes()).padStart(2, '0');
		    const seconds = String(now.getSeconds()).padStart(2, '0');
		
		    return `${year}${month}${day}${hours}${minutes}${seconds}`;
		}

        /**
         * 更新统计信息
         */
        function updateStats() {
            const input = document.getElementById('urlInput').value.trim();
            const urls = input ? input.split('\n').filter(url => url.trim()) : [];
            
            // 统计短链接（假设短于30个字符的为短链接）
            const shortUrls = urls.filter(url => url.trim().length < 30);
            
            // 简单的URL验证
            const validUrls = urls.filter(url => {
                try {
                    new URL(url.trim());
                    return true;
                } catch {
                    return false;
                }
            });

            document.getElementById('totalUrls').textContent = urls.length;
            document.getElementById('validUrls').textContent = validUrls.length;
            document.getElementById('shortUrls').textContent = shortUrls.length;
            document.getElementById('generatedQr').textContent = qrData.length;
        }

        /**
         * 显示提示消息
         * @param {string} message - 消息内容
         * @param {string} type - 消息类型
         */
        function showAlert(message, type = 'warning') {
            const container = document.getElementById('alertContainer');
            container.innerHTML = `<div class="alert alert-${type}">${message}</div>`;
            setTimeout(() => {
                container.innerHTML = '';
            }, 5000);
        }

        /**
         * 设置生成按钮为loading状态
         */
        function setGenerateButtonLoading() {
            const btn = document.getElementById('generateBtn');
            btn.innerHTML = '<span class="loading-icon">🔄</span> 生成中...';
            btn.classList.add('btn-loading');
            btn.disabled = true;
        }

        /**
         * 恢复生成按钮为正常状态
         */
        function resetGenerateButton() {
            const btn = document.getElementById('generateBtn');
            btn.innerHTML = '📱 批量生成二维码';
            btn.classList.remove('btn-loading');
            btn.disabled = false;
        }

        /**
         * 生成包含文件名的二维码图片
         * @param {string} qrDataUrl - 原始二维码的base64数据
         * @param {string} filename - 要显示的文件名
         * @param {function} callback - 回调函数，接收生成的图片数据
         */
        function generateQRCodeWithFilename(qrDataUrl, filename, callback) {
            const canvas = document.createElement('canvas');
            const ctx = canvas.getContext('2d');
            const img = new Image();
            
            img.onload = function() {
                // 设置画布尺寸 - 文字区域高度 + 二维码高度
                const qrSize = 200;
                const textHeight = 40;
                const padding = 10;
                
                canvas.width = qrSize + (padding * 2);
                canvas.height = qrSize + textHeight + (padding * 3);
                
                // 设置背景为白色
                ctx.fillStyle = '#ffffff';
                ctx.fillRect(0, 0, canvas.width, canvas.height);
                
                // 设置文字样式 - 改为灰色
                ctx.fillStyle = '#888888';
                ctx.font = 'bold 12px Arial, sans-serif';
                ctx.textAlign = 'center';
                ctx.textBaseline = 'middle';
                
                // 计算文字位置 - 放在图片上方
                const textX = canvas.width / 2;
                const textY = padding + textHeight / 2;
                
                // 绘制文件名
                ctx.fillText(filename, textX, textY);
                
                // 绘制二维码 - 放在文字下方
                ctx.drawImage(img, padding, padding + textHeight, qrSize, qrSize);
                
                // 转换为base64并回调
                const finalDataUrl = canvas.toDataURL('image/png');
                callback(finalDataUrl);
            };
            
            img.src = qrDataUrl;
        }

        /**
         * 批量生成二维码
         */
        function generateAllQRCodes() {
            if (isGenerating) {
                showAlert('正在生成中，请稍等...', 'warning');
                return;
            }

            const input = document.getElementById('urlInput').value.trim();
            const container = document.getElementById('qrcodeContainer');
            const progressContainer = document.getElementById('progressContainer');
            const progressBar = document.getElementById('progressBar');
            const previewInfo = document.getElementById('previewInfo');
             
            container.innerHTML = '';
            qrData = [];
            previewInfo.style.display = 'none';

            if (!input) {
                showAlert('请输入至少一个 URL 地址', 'error');
                return;
            }

            const urls = input.split('\n').filter(url => url.trim());
            
            // 检查URL数量限制
            if (urls.length > 5000) {
                showAlert(`输入的URL数量为 ${urls.length} 个，超过最大限制5000个，请减少URL数量`, 'error');
                return;
            }

            if (urls.length === 0) {
                showAlert('没有找到有效的URL地址', 'error');
                return;
            }

            isGenerating = true;
            setGenerateButtonLoading();
            progressContainer.style.display = 'block';
            showAlert(`开始生成 ${urls.length} 个二维码...`, 'success');

            let completed = 0;
            const total = urls.length;

            urls.forEach((url, index) => {
                const trimmedUrl = url.trim();
                 
                // 验证URL格式
                try {
                    new URL(trimmedUrl);
                } catch {
                    completed++;
                    updateProgress(completed, total);
                    showAlert(`第${index + 1}个URL格式无效: ${trimmedUrl}`, 'error');
                    checkCompletion(completed, total);
                    return;
                }

                QRCode.toDataURL(trimmedUrl, { 
                    errorCorrectionLevel: 'H',
                    width: 200,
                    margin: 1
                }, function (err, dataUrl) {
                    if (err) {
                        completed++;
                        console.error(`生成二维码失败：${trimmedUrl}`, err);
                        updateProgress(completed, total);
                        checkCompletion(completed, total);
                        return;
                    }

                    // 生成包含文件名的二维码图片
                    const urlLast7 = trimmedUrl.slice(-7);
                    const filename = sanitizeFilename(`${index + 1}_${urlLast7}.png`);
                    
                    generateQRCodeWithFilename(dataUrl, filename, function(finalDataUrl) {
                        completed++;
                        
                        // 存储二维码数据
                        qrData.push({
                            url: trimmedUrl,
                            dataUrl: finalDataUrl,
                            index: index + 1,
                            filename: filename
                        });

                        // 只显示前8个二维码预览
                        if (index < 8) {
                            // 创建显示元素
                            const wrapper = document.createElement('div');
                            wrapper.className = 'qrcode-item';

                            // 添加序号标题
                            const indexTitle = document.createElement('div');
                            indexTitle.style.fontSize = '16px';
                            indexTitle.style.fontWeight = 'bold';
                            indexTitle.style.color = '#007bff';
                            indexTitle.style.marginBottom = '10px';
                            indexTitle.textContent = `#${index + 1}`;

                            const img = document.createElement('img');
                            img.src = finalDataUrl;
                            img.alt = `QR Code for ${trimmedUrl}`;

                            const urlText = document.createElement('div');
                            urlText.className = 'url-text';
                            urlText.textContent = trimmedUrl;

                            const downloadBtn = document.createElement('button');
                            downloadBtn.className = 'btn-info';
                            downloadBtn.style.marginTop = '10px';
                            downloadBtn.style.padding = '5px 10px';
                            downloadBtn.style.fontSize = '12px';
                            downloadBtn.textContent = `下载 #${index + 1}`;
                            downloadBtn.onclick = () => downloadSingleQRCode(finalDataUrl, index + 1, trimmedUrl);

                            wrapper.appendChild(indexTitle);
                            wrapper.appendChild(img);
                            wrapper.appendChild(urlText);
                            wrapper.appendChild(downloadBtn);
                            container.appendChild(wrapper);
                        }

                        updateProgress(completed, total);
                        updateStats();
                        checkCompletion(completed, total);
                    });
                });
            });
        }

        /**
         * 检查生成是否完成
         * @param {number} completed - 已完成数量
         * @param {number} total - 总数量
         */
        function checkCompletion(completed, total) {
            if (completed === total) {
                isGenerating = false;
                resetGenerateButton();
                const progressContainer = document.getElementById('progressContainer');
                const previewInfo = document.getElementById('previewInfo');
                
                progressContainer.style.display = 'none';
                
                // 显示预览说明
                if (qrData.length > 0) {
                    previewInfo.style.display = 'block';
                }
                
                if (total > 8) {
                    showAlert(`成功生成 ${qrData.length} 个二维码！（页面仅显示前8个预览，全部二维码已生成完成，文件名已嵌入图片中）`, 'success');
                } else {
                    showAlert(`成功生成 ${qrData.length} 个二维码！（文件名已嵌入图片中）`, 'success');
                }
            }
        }

        /**
         * 更新进度条
         * @param {number} completed - 已完成数量
         * @param {number} total - 总数量
         */
        function updateProgress(completed, total) {
            const percent = (completed / total) * 100;
            document.getElementById('progressBar').style.width = percent + '%';
        }

        /**
         * 下载单个二维码图片
         * @param {string} dataUrl - 图片数据URL
         * @param {number} index - 序号
         * @param {string} url - 原始URL
         */
        function downloadSingleQRCode(dataUrl, index, url) {
            // 获取URL的后7个字符
            const urlLast7 = url.slice(-7);
            const filename = sanitizeFilename(`${index}_${urlLast7}`);
            const a = document.createElement('a');
            a.href = dataUrl;
            a.download = `${filename}.png`;
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
        }

        /**
         * 批量下载所有二维码图片
         */
        async function downloadAllQRCodeImages() {
            if (qrData.length === 0) {
                showAlert('请先生成二维码', 'warning');
                return;
            }

            try {
                showAlert(`正在打包 ${qrData.length} 个二维码图片...`, 'success');
                
                // 创建ZIP压缩包
                const zip = new JSZip();
                
                // 添加所有二维码图片到压缩包
                qrData.forEach((item, index) => {
                    // 使用存储的文件名
                    const filename = item.filename;
                    
                    // 将base64数据转换为二进制数据
                    const base64Data = item.dataUrl.split(',')[1];
                    zip.file(filename, base64Data, { base64: true });
                });
                
                // 生成压缩包
                const content = await zip.generateAsync({ type: "blob" });
                
                // 生成文件名
                const timestamp = getCurrentTimestamp();
                const zipFilename = `二维码图片包[日期${timestamp},共${qrData.length}张].zip`;
                
                // 下载压缩包
                const url = window.URL.createObjectURL(content);
                const a = document.createElement('a');
                a.href = url;
                a.download = zipFilename;
                document.body.appendChild(a);
                a.click();
                document.body.removeChild(a);
                window.URL.revokeObjectURL(url);
                
                showAlert(`✅ 压缩包下载完成: ${zipFilename}`, 'success');
                
            } catch (error) {
                console.error('打包下载失败:', error);
                showAlert('❌ 压缩包生成失败，请重试', 'error');
            }
        }

        /**
         * 导出到Excel文件
         */
        async function exportToExcel() {
            if (qrData.length === 0) {
                showAlert('请先生成二维码', 'warning');
                return;
            }

            try {
                showAlert('正在生成包含图片的Excel文件，请稍等...', 'success');
                
                // 创建新的工作簿
                const workbook = new ExcelJS.Workbook();
                const worksheet = workbook.addWorksheet('二维码数据');

                // 设置列宽和表头
                worksheet.columns = [
                    { header: '序号', key: 'index', width: 10 },
                    { header: '短链接', key: 'url', width: 60 },
                    { header: '二维码图片', key: 'qrcode', width: 25 }
                ];

                // 设置表头样式
                worksheet.getRow(1).font = { bold: true, size: 12 };
                worksheet.getRow(1).alignment = { vertical: 'middle', horizontal: 'center' };
                worksheet.getRow(1).fill = {
                    type: 'pattern',
                    pattern: 'solid',
                    fgColor: { argb: 'FFE0E0E0' }
                };

                // 添加数据并插入图片
                for (let i = 0; i < qrData.length; i++) {
                    const item = qrData[i];
                    const rowNumber = i + 2; // 从第2行开始（第1行是表头）
                    
                    // 添加基本数据
                    worksheet.addRow({
                        index: item.index,
                        url: item.url,
                        qrcode: '' // 图片列暂时为空
                    });

                    // 设置行高以适应图片
                    worksheet.getRow(rowNumber).height = 150;
                    
                    // 将base64图片数据转换为buffer
                    const base64Data = item.dataUrl.split(',')[1];
                    const imageBuffer = Uint8Array.from(atob(base64Data), c => c.charCodeAt(0));
                    
                    // 添加图片到工作簿
                    const imageId = workbook.addImage({
                        buffer: imageBuffer,
                        extension: 'png',
                    });

                    // 将图片插入到指定单元格
                    worksheet.addImage(imageId, {
                        tl: { col: 2, row: rowNumber - 1 }, // 图片左上角位置 (C列，对应行)
                        ext: { width: 150, height: 140 }     // 图片大小
                    });

                    // 设置单元格对齐方式
                    worksheet.getCell(`A${rowNumber}`).alignment = { vertical: 'middle', horizontal: 'center' };
                    worksheet.getCell(`B${rowNumber}`).alignment = { vertical: 'middle', horizontal: 'left' };
                    worksheet.getCell(`C${rowNumber}`).alignment = { vertical: 'middle', horizontal: 'center' };
                }

                // 添加边框
                for (let i = 1; i <= qrData.length + 1; i++) {
                    ['A', 'B', 'C'].forEach(col => {
                        const cell = worksheet.getCell(`${col}${i}`);
                        cell.border = {
                            top: { style: 'thin' },
                            left: { style: 'thin' },
                            bottom: { style: 'thin' },
                            right: { style: 'thin' }
                        };
                    });
                }

                // 生成文件名
                const timestamp = getCurrentTimestamp();
                const filename = `URL转二维码[日期${timestamp},链接数${qrData.length}个].xlsx`;

                // 生成Excel文件并下载
                const buffer = await workbook.xlsx.writeBuffer();
                const blob = new Blob([buffer], { 
                    type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' 
                });
                
                const url = window.URL.createObjectURL(blob);
                const a = document.createElement('a');
                a.href = url;
                a.download = filename;
                document.body.appendChild(a);
                a.click();
                document.body.removeChild(a);
                window.URL.revokeObjectURL(url);
                
                showAlert(`✅ Excel文件已导出: ${filename}`, 'success');
                
                // 成功提示
                setTimeout(() => {
                    showAlert('🎉 二维码图片（含文件名）已成功嵌入Excel文件中！每个图片对应其URL链接。', 'success');
                }, 2000);

            } catch (error) {
                console.error('导出Excel失败:', error);
                showAlert('❌ 导出Excel文件失败，请重试', 'error');
            }
        }

        /**
         * 清空所有数据
         */
        function clearAll() {
            if (confirm('确定要清空所有数据吗？')) {
                document.getElementById('urlInput').value = '';
                document.getElementById('qrcodeContainer').innerHTML = '';
                document.getElementById('alertContainer').innerHTML = '';
                document.getElementById('progressContainer').style.display = 'none';
                document.getElementById('previewInfo').style.display = 'none';
                qrData = [];
                updateStats();
                showAlert('已清空所有数据', 'success');
            }
        }

        /**
         * 清理文件名，移除不合法字符
         * @param {string} str - 原始字符串
         * @returns {string} 清理后的文件名
         */
        function sanitizeFilename(str) {
            return str.replace(/[\\\/\:\*\?\"\<\>\|]/g, '_').substring(0, 50);
        }

        // 页面加载时初始化统计
        window.onload = function() {
            updateStats();
        };
    </script>
</body>
</html> 